package server;
import poker.*;
import java.io.IOException;
import java.util.LinkedHashMap;
import java.util.Map;
import org.apache.commons.lang.ArrayUtils;
import com.google.gson.Gson;
import javax.servlet.Servlet;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class gameServlet extends HttpServlet implements Servlet {
    //implement compulsory variable
	private static final long serialVersionUID = 1L;
	@Override
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		String action = request.getParameter("action");
		String[] actions = {"get_game", "restart_game", "person_fold", "person_raise", "person_call", "person_check", "get_next_move"};
		//index or -1 if not found
		int actionIndex = ArrayUtils.indexOf(actions, action);
		
		switch (actionIndex) {
			case 0: //get_game
				this.getGame(request, response);
				break;
			case 1: //restart
				this.restartGame(request, response);
				break;
			case 2: //person folded
				this.personAction("fold", request, response);
				break;
			case 3: //person raised
				this.personAction("raise", request, response);
				break;
			case 4: //person called
				this.personAction("call", request, response);
				break;
			case 5: //person checked
				this.personAction("call", request, response);
				break;
			case 6: //get next move				
				this.getNextMove(request, response);
				break;
			default:
				Map<String, String> result = new LinkedHashMap<String, String>();
				result.put("error", "not found");
				this.respondJson(response, result);
				break;		
		}		
	}
	private void respondJson(HttpServletResponse resp, Map<String, String> json) throws IOException {
		String result = new Gson().toJson(json);
	    resp.setContentType("application/json");
	    resp.setCharacterEncoding("UTF-8");
	    resp.getWriter().write(result);		
	}
	
	private void restartGame(HttpServletRequest req, HttpServletResponse resp) throws IOException {
		PokerGame game = 
			(PokerGame)req.getSession(true).getAttribute("pokerappgame");
		if (game != null) {
			req.getSession().setAttribute("pokerappgame", null);
		}
		Map<String, String> result = new LinkedHashMap<String, String>();
		result.put("response", "restarted");
		this.respondJson(resp, result);
	}
	
	//get the current game from session or create a new one and output json data of scores
	private void getGame(HttpServletRequest req, HttpServletResponse resp) throws IOException {
		PokerGame game = (PokerGame)req.getSession(true).getAttribute("pokerappgame");
		
		if(game == null) {
			int players = 10;
			int startingScore = 1500;
			int personPosition = (int)(10.0 * Math.random());
			game = new PokerGame(players, startingScore, personPosition);			
			req.getSession().setAttribute("pokerappgame", game);
		}
		Map<String, String> result = new LinkedHashMap<String, String>();
		if (game.getGameState() == "over") game.nextRound();
		
		for (int i = 0; i < game.getPlayerCount(); i++) {
			result.put("player_score_"+i, Integer.toString(game.getPlayer(i).getScore()));			
		}		 
		result.put("person_card1", game.getPlayer(game.getPersonPosition()).getCard1().toString());
		result.put("person_card2", game.getPlayer(game.getPersonPosition()).getCard2().toString());
		//TODO: next position is wrong when game was previously advanced
		result.put("next_position", Integer.toString(game.getNextPlayer()));
		result.put("person_position", Integer.toString(game.getPersonPosition()));
		result.put("dealer_position", Integer.toString(game.getDealerPosition()));
		result.put("big_blind", Integer.toString(game.getBigBlind()));
		result.put("pot", Integer.toString(game.getPot()));
		result.put("player_count", Integer.toString(game.getPlayerCount()));
		result.put("flop", "false");
		this.respondJson(resp, result);
	}
	//get the move of computer generated player
	private void getNextMove(HttpServletRequest req, HttpServletResponse resp) throws IOException {
		PokerGame game = (PokerGame)req.getSession(true).getAttribute("pokerappgame");
		Map<String, String> result = new LinkedHashMap<String, String>();
		if(game == null) {			
			result.put("error", "start a game first");
			this.respondJson(resp, result);			
		} else {
			result.put("position", Integer.toString(game.getNextPlayer()));
			int current_position = game.getNextPlayer();
			game.nextMove();			
			if (game.getGameState() == "flop") {
				result.put("flop", "true");
				if (game.getCard5() != null) result.put("card5", game.getCard5().toString());
				else if (game.getCard4() != null) result.put("card4", game.getCard4().toString());
				else {
					result.put("card1", game.getCard1().toString());
					result.put("card2", game.getCard2().toString());
					result.put("card3", game.getCard3().toString());					
				}
				result.put("pot", Integer.toString(game.getPot()));
				//add all player scores
				int players = game.getPlayerCount();
				for (int i = 0; i < players; i++) {
					result.put("player_score_"+i, Integer.toString(game.getPlayer(i).getScore()));			
				}
				//add all player scores
				for (int i = 0; i < players; i++) {
					result.put("player_status_"+i, game.getPlayer(i).getStatus());			
				}
			} else if (game.getGameState() == "over") {
				result.put("over", "true");
				for (int i = 0; i < game.getPlayerCount(); i++) {
					if (game.getPlayer(i).getStatus() != "fold") {
						result.put("player_score_"+Integer.toString(i), Integer.toString(game.getPlayer(i).getScore()));
						result.put("player_status_"+Integer.toString(i), game.getPlayer(i).getStatus().toString());
						result.put("player_card1_"+Integer.toString(i), game.getPlayer(i).getCard1().toString());
						result.put("player_card2_"+Integer.toString(i), game.getPlayer(i).getCard2().toString());						
					}
				}
				result.put("winner_position", Integer.toString(game.getWinnerPosition()));
				this.respondJson(resp, result);
				return;
			} 
			else {
				result.put("flop", "false");
			}
			result.put("status", game.getPlayer(current_position).getStatus());
			result.put("score", Integer.toString(game.getPlayer(current_position).getScore()));
			result.put("next_position", Integer.toString(game.getNextPlayer()));
			if (game.isPersonNext()) {
				result.put("person", "true");
				result.put("person_call", Integer.toString(game.getPlayer(game.getPersonPosition()).getToCall()));
			} else 	result.put("person", "false");
			result.put("person", (game.isPersonNext())?"true":"false");
			result.put("pot", Integer.toString(game.getPot()));
			this.respondJson(resp, result);			
		}
	}
	private void personAction(String action, HttpServletRequest req, HttpServletResponse resp)throws IOException {
		PokerGame game = (PokerGame)req.getSession(true).getAttribute("pokerappgame");
		Map<String, String> result = new LinkedHashMap<String, String>();
		if (game == null) {
			result.put("error", "start a game first");
			this.respondJson(resp, result);
		} else {
			result.put("position", Integer.toString(game.getNextPlayer()));
			if (action == "fold")			game.personFoldAction();
			else if (action == "call") 		game.personCallAction();
			else if (action == "raise")		game.personRaiseAction();
			else {
				result.put("error", "An error occured.");
				this.respondJson(resp, result);
				return;
			}
			if (game.getGameState() == "flop") {
				result.put("flop", "true");
				if (game.getCard5() != null) result.put("card5", game.getCard5().toString());
				else if (game.getCard4() != null) result.put("card4", game.getCard4().toString());
				else {
					result.put("card1", game.getCard1().toString());
					result.put("card2", game.getCard2().toString());
					result.put("card3", game.getCard3().toString());					
				}
				result.put("pot", Integer.toString(game.getPot()));
				//add all player scores
				int players = game.getPlayerCount();
				for (int i = 0; i < players; i++) {
					result.put("player_score_"+i, Integer.toString(game.getPlayer(i).getScore()));			
				}
				//add all player scores
				for (int i = 0; i < players; i++) {
					result.put("player_status_"+i, game.getPlayer(i).getStatus());			
				}
			} else result.put("flop", "false");
			result.put("pot", Integer.toString(game.getPot()));
			result.put("status", game.getPlayer(game.getPersonPosition()).getStatus());
			result.put("score",  Integer.toString(game.getPlayer(game.getPersonPosition()).getScore()));
			result.put("next_position", Integer.toString(game.getNextPlayer()));
			result.put("person", (game.isPersonNext())?"true":"false");
			this.respondJson(resp, result);
		}
	}
}
